﻿using System.IO.Hashing;
using System.Security.Cryptography;

namespace AspNetCore.Tools.DataEncryption;

/// <summary>
/// Hash 加密
/// </summary>
public class HashEncryption
{
    /// <summary>
    /// 使用 MD5 算法计算哈希，包含 32 个字符
    /// </summary>
    /// <remarks>
    /// 微软官方表示已发现 MD5 和 SHA-1 算法不安全，建议改用 SHA-2。 SHA-2 包括 SHA256、SHA384 和 SHA512。
    /// 参考说明：https://learn.microsoft.com/zh-cn/dotnet/standard/security/cryptographic-services#hash-values
    /// </remarks>
    /// <param name="bytes">字节数组</param>
    /// <param name="uppercase">是否输出大写</param>
    /// <param name="is16">是否输出 16 位</param>
    /// <returns>哈希字符串</returns>
    public static string MD5Encrypt(byte[] bytes, bool uppercase = false, bool is16 = false)
    {
        var hashBytes = MD5.HashData(bytes);
        var md5String = hashBytes.ToHexString(uppercase);
        var hash = !is16 ? md5String : md5String.Substring(8, 16);
        return hash;
    }

    /// <summary>
    /// 使用 SHA1 算法计算哈希，包含 40 个字符
    /// </summary>
    /// <remarks>
    /// 微软官方表示已发现 MD5 和 SHA-1 算法不安全，建议改用 SHA-2。 SHA-2 包括 SHA256、SHA384 和 SHA512。
    /// 参考说明：https://learn.microsoft.com/zh-cn/dotnet/standard/security/cryptographic-services#hash-values
    /// </remarks>
    /// <param name="bytes">字节数组</param>
    /// <param name="uppercase">是否输出大写</param>
    /// <returns></returns>
    public static string SHA1Encrypt(byte[] bytes, bool uppercase = false)
    {
        var hashBytes = SHA1.HashData(bytes);
        return hashBytes.ToHexString(uppercase);
    }

    /// <summary>
    /// 使用 SHA256 算法计算哈希，包含 64 个字符
    /// </summary>
    /// <param name="bytes">字节数组</param>
    /// <param name="uppercase">是否输出大写</param>
    /// <returns></returns>
    public static string SHA256Encrypt(byte[] bytes, bool uppercase = false)
    {
        var hashBytes = SHA256.HashData(bytes);
        return hashBytes.ToHexString(uppercase);
    }

    /// <summary>
    /// 使用 CRC-32 算法计算哈希
    /// </summary>
    /// <param name="bytes"></param>
    /// <param name="uppercase"></param>
    /// <returns></returns>
    public static string Crc32Encrypt(byte[] bytes, bool uppercase = false)
    {
        var hashBytes = Crc32.Hash(bytes);
        var reverseHashBytes = hashBytes.Reverse();
        return reverseHashBytes.ToHexString(uppercase);
    }

    /// <summary>
    /// 使用 CRC-32 算法计算哈希
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="uppercase"></param>
    /// <returns></returns>
    public static string Crc32Encrypt(Stream stream, bool uppercase = false)
    {
        var crc = new Crc32();
        crc.Append(stream);
        var hashBytes = crc.GetHashAndReset();
        var reverseHashBytes = hashBytes.Reverse();
        return hashBytes.ToHexString(uppercase);
    }

    /// <summary>
    /// 使用 CRC-32 算法计算哈希
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="uppercase"></param>
    /// <returns></returns>
    public static async ValueTask<string> Crc32EncryptAsync(Stream stream, bool uppercase = false)
    {
        var crc = new Crc32();
        await crc.AppendAsync(stream);
        var hashBytes = crc.GetHashAndReset();
        var reverseHashBytes = hashBytes.Reverse();
        return hashBytes.ToHexString(uppercase);
    }
}
